// Ignore argument count for test functions.
#![allow(clippy::too_many_arguments)]

use std::collections;

use collections::HashSet;
use ndarray::{array, Array2};
use rstest::rstest;

use crate::tests::common::assert_expected_result_or_error;
use crate::tests::fixtures::{
    rand_float,
    rand_string,
    rand_usize,
    random_tile_type,
    RANDOM_STRINGS,
    RANDOM_USIZE,
};
use crate::tiling::slot_grid::*;
use crate::tiling::tiles::{Connectors, Tile, TileContent};
use crate::Error;

// noinspection DuplicatedCode
#[rstest]
// region one row, one col, three tiles, no border_tile_id, success
#[case::one_row_one_col_three_tiles_no_border_tile_id_success(
    1,
    1,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 3),
                    east: rand_usize(1, 3),
                    south: rand_usize(1, 4),
                    west: rand_usize(1, 4),
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 5),
                    east: rand_usize(1, 5),
                    south: rand_usize(1, 6),
                    west: rand_usize(1, 6),
                },
                weight: rand_float() + 10.2,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 7),
                    east: rand_usize(1, 7),
                    south: rand_usize(1, 8),
                    west: rand_usize(1, 8),
                },
                weight: rand_float(),
            },
        ],
        horizontal_connector_names: vec![
            "".to_string(),
            "".to_string(),
            "".to_string(),
            "".to_string(),
            RANDOM_STRINGS[3].clone(),
        ],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
    ],
    Some(()),
    None,
)]
// endregion
// region one row, one col, three tiles, valid border_tile_id, success
#[case::one_row_one_col_three_tiles_valid_border_tile_id_success(
    1,
    1,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 3),
                    east: rand_usize(1, 3),
                    south: rand_usize(1, 4),
                    west: 3,
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 1,
                    east: 4,
                    south: 3,
                    west: 3,
                },
                weight: -1.0 * rand_float(),
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 3,
                    east: 3,
                    south: 1,
                    west: 4,
                },
                weight: rand_float(),
            },
        ],
        horizontal_connector_names: vec![
            "".to_string(),
            "".to_string(),
            "".to_string(),
            "".to_string(),
            RANDOM_STRINGS[3].clone(),
        ],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    Some(1),
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(2),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
    ],
    Some(()),
    None,
)]
// endregion
// region two rows, three cols, four tiles, valid border_tile_id, success
#[case::two_rows_three_cols_four_tiles_valid_border_tile_id_success(
    2,
    3,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float(),
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 3,
                    south: *RANDOM_USIZE + 3,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -1.0 * rand_float(),
            },
            Tile {
                id: 3,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -7.3 * rand_float() - 1.0,
            },
            Tile {
                id: 4,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 0,
                    east: 0,
                    south: *RANDOM_USIZE + 2,
                    west: 0,
                },
                weight: -70.3 * rand_float() - 2.0,
            },
            Tile {
                id: 5,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 4,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 92.0,
            },
        ],
        horizontal_connector_names: vec![
            "".to_string(),
            "".to_string(),
            "".to_string(),
            "".to_string(),
            RANDOM_STRINGS[3].clone(),
        ],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    Some(4),
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(2),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(0),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(3),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
    ],
    Some(()),
    None,
)]
// endregion
// region two rows, three cols, four tiles, no border_tile_id, success
#[case::two_rows_three_cols_four_tiles_no_border_tile_id_success(
    2,
    3,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float(),
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 3,
                    south: *RANDOM_USIZE + 3,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -1.0 * rand_float(),
            },
            Tile {
                id: 3,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -7.3 * rand_float() - 1.0,
            },
            Tile {
                id: 4,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 0,
                    east: 0,
                    south: *RANDOM_USIZE + 2,
                    west: 0,
                },
                weight: -70.3 * rand_float() - 2.0,
            },
            Tile {
                id: 5,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 4,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 92.0,
            },
        ],
        horizontal_connector_names: vec![
            "".to_string(),
            "".to_string(),
            "".to_string(),
            "".to_string(),
            RANDOM_STRINGS[3].clone(),
        ],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(2),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
    ],
    Some(()),
    None,
)]
// endregion
// region two rows, three cols, four tiles, no border_tile_id, failure
#[case::two_rows_three_cols_four_tiles_no_border_tile_id_failure(
    2,
    3,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float(),
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 3,
                    south: *RANDOM_USIZE + 3,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 4,
                },
                weight: -1.0 * rand_float(),
            },
            Tile {
                id: 3,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -7.3 * rand_float() - 1.0,
            },
            Tile {
                id: 4,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 0,
                    east: 0,
                    south: *RANDOM_USIZE + 2,
                    west: 0,
                },
                weight: -70.3 * rand_float() - 2.0,
            },
            Tile {
                id: 5,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 4,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 92.0,
            },
        ],
        horizontal_connector_names: {
            let mut names = vec![
                RANDOM_STRINGS[3].clone(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
            ];
            names.insert(*RANDOM_USIZE + 3, RANDOM_STRINGS[6].clone());
            names
        },
        vertical_connector_names: {
            let mut names = vec![
                RANDOM_STRINGS[5].clone(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
            ];
            names.insert(*RANDOM_USIZE + 2, RANDOM_STRINGS[4].clone());
            names
        },
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            None,
            None,
        ],
    ],
    None,
    Some(Error::TileNotFoundException(format!(
        "no tiles available with Connectors {{ north: “{}”, east: “{}”, south: “{}”, west: “{}” }}",
        RANDOM_STRINGS[4],
        RANDOM_STRINGS[3],
        RANDOM_STRINGS[5],
        RANDOM_STRINGS[6],
    ))),
)]
// endregion
// region two rows, three cols, four tiles, no border_tile_id, failure
#[case::two_rows_three_cols_four_tiles_no_border_tile_id_failure(
    2,
    3,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float(),
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 3,
                    south: *RANDOM_USIZE + 3,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 5.3,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 4,
                },
                weight: -1.0 * rand_float(),
            },
            Tile {
                id: 3,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 3,
                },
                weight: -7.3 * rand_float() - 1.0,
            },
            Tile {
                id: 4,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: 0,
                    east: 0,
                    south: *RANDOM_USIZE + 2,
                    west: 0,
                },
                weight: -70.3 * rand_float() - 2.0,
            },
            Tile {
                id: 5,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 4,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 92.0,
            },
        ],
        horizontal_connector_names: {
            let mut names = vec![
                RANDOM_STRINGS[3].clone(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
            ];
            names.insert(*RANDOM_USIZE + 3, RANDOM_STRINGS[6].clone());
            names
        },
        vertical_connector_names: {
            let mut names = vec![
                RANDOM_STRINGS[5].clone(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
                "".to_string(),
            ];
            names.insert(*RANDOM_USIZE + 2, RANDOM_STRINGS[4].clone());
            names
        },
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Priority,
    array![
        [
            None,
            None,
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            Some(GridSlot {
                tile_id: Some(5),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(1),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
            None,
            None,
        ],
    ],
    None,
    Some(Error::TileNotFoundException(format!(
        "no tiles available with Connectors {{ north: “{}”, east: “{}”, south: “{}”, west: “{}” }}",
        RANDOM_STRINGS[4],
        RANDOM_STRINGS[3],
        RANDOM_STRINGS[5],
        RANDOM_STRINGS[6],
    ))),
)]
// endregion
// region two rows, three cols, two tiles, no border_tile_id, random selection, failure
#[case::two_rows_three_cols_two_tiles_no_border_tile_id_random_selection_failure(
    2,
    3,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 3,
                    east: *RANDOM_USIZE + 2,
                    south: *RANDOM_USIZE + 2,
                    west: *RANDOM_USIZE + 2,
                },
                weight: -0.1,
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: *RANDOM_USIZE + 2,
                    east: *RANDOM_USIZE + 3,
                    south: *RANDOM_USIZE + 3,
                    west: *RANDOM_USIZE + 2,
                },
                weight: rand_float() + 5.3,
            },
        ],
        horizontal_connector_names: vec![RANDOM_STRINGS[3].clone()],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Random,
    array![
        [None, None, None, None],
        [None, None, None, None],
        [None, None, None, None],
    ],
    None,
    Some(Error::ValueError(
        "selecting a tile randomly failed: A weight is negative, too large or not a valid number"
        .to_string()
    )),
)]
// endregion
// region one row, one col, three tiles, no border_tile_id, random selection, success
#[case::one_row_one_col_three_tiles_no_border_tile_id_success(
    1,
    1,
    TileList {
        tiles: vec![
            Tile {
                id: 0,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 3),
                    east: rand_usize(1, 3),
                    south: rand_usize(1, 4),
                    west: rand_usize(1, 4),
                },
                weight: 0.0,
            },
            Tile {
                id: 1,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 5),
                    east: rand_usize(1, 5),
                    south: rand_usize(1, 6),
                    west: rand_usize(1, 6),
                },
                weight: 0.0,
            },
            Tile {
                id: 2,
                name: rand_string(rand_usize(0, 2)),
                content: TileContent::Empty,
                connectors: Connectors {
                    north: rand_usize(1, 7),
                    east: rand_usize(1, 7),
                    south: rand_usize(1, 8),
                    west: rand_usize(1, 8),
                },
                weight: rand_float() + 3.9,
            },
        ],
        horizontal_connector_names: vec![
            RANDOM_STRINGS[4].clone(),
            RANDOM_STRINGS[5].clone(),
            RANDOM_STRINGS[6].clone(),
            RANDOM_STRINGS[7].clone(),
            RANDOM_STRINGS[3].clone(),
        ],
        vertical_connector_names: vec![RANDOM_STRINGS[5].clone()],
        tile_type: random_tile_type(),
    },
    None,
    TileSelectionPolicy::Random,
    array![
        [
            None,
            None,
        ],
        [
            None,
            Some(GridSlot {
                tile_id: Some(2),
                direction: None,
                predecessor: None,
                exposed_edges: vec![],
                excluded_connectors: HashSet::new(),
            }),
        ],
    ],
    Some(()),
    None,
)]
// endregion
fn test_slot_grid_populate_simple(
    #[case] num_rows: usize,
    #[case] num_cols: usize,
    #[case] tile_list: TileList,
    #[case] border_tile_id: Option<usize>,
    #[values(MissingTilePolicy::Avoid, MissingTilePolicy::Exit)]
    missing_tile_policy: MissingTilePolicy,
    #[case] tile_selection_policy: TileSelectionPolicy,
    #[values(
        VacancyPolicy::Ignore,
        VacancyPolicy::Avoid,
        VacancyPolicy::AvoidStrict
    )]
    vacancy_policy: VacancyPolicy,
    #[case] expected_slot_grid: Array2<Option<GridSlot>>,
    #[case] expected_result: Option<()>,
    #[case] expected_error: Option<Error>,
) {
    let mut slot_grid = SlotGrid::new(
        num_rows,
        num_cols,
        tile_list,
        border_tile_id,
        missing_tile_policy,
        tile_selection_policy,
        vacancy_policy,
    )
    .expect("the number of rows, columns as well as the border tile ID should be valid");
    let result = slot_grid.populate_simple();

    assert_expected_result_or_error(result, expected_result, expected_error);
    assert_eq!(slot_grid.grid, expected_slot_grid);
}
